from typing import List, Optional
from uuid import UUID

from fastapi_template.models import Permission, Role

from .dto import PermissionCreateDTO, PermissionDTO, PermissionUpdateDTO
from .facade import PermissionFacade


class PermissionFacadeImpl(PermissionFacade):
    """Implementation of the permission domain facade."""

    async def create_permission(
            self, permission_data: PermissionCreateDTO) -> PermissionDTO:
        """Create a new permission."""
        permission = await Permission.create(
            name=permission_data.name,
            code=permission_data.code,
            description=permission_data.description)
        return PermissionDTO.model_validate(permission)

    async def get_permission_by_id(
            self, permission_id: UUID) -> Optional[PermissionDTO]:
        """Get permission by ID."""
        permission = await Permission.get_or_none(id=permission_id)
        return PermissionDTO.model_validate(permission) if permission else None

    async def get_permission_by_code(self,
                                     code: str) -> Optional[PermissionDTO]:
        """Get permission by code."""
        permission = await Permission.get_or_none(code=code)
        return PermissionDTO.model_validate(permission) if permission else None

    async def get_all_permissions(self) -> List[PermissionDTO]:
        """Get all permissions."""
        permissions = await Permission.all()
        return [
            PermissionDTO.model_validate(permission)
            for permission in permissions
        ]

    async def update_permission(
            self, permission_id: UUID,
            permission_data: PermissionUpdateDTO) -> Optional[PermissionDTO]:
        """Update permission information."""
        permission = await Permission.get_or_none(id=permission_id)
        if not permission:
            return None

        update_data = permission_data.model_dump(exclude_unset=True)
        if update_data:
            await permission.update_from_dict(update_data).save()

        return PermissionDTO.model_validate(permission)

    async def delete_permission(self, permission_id: UUID) -> bool:
        """Delete permission by ID."""
        permission = await Permission.get_or_none(id=permission_id)
        if not permission:
            return False
        await permission.delete()
        return True

    async def get_role_permissions(self, role_id: UUID) -> List[PermissionDTO]:
        """Get all permissions of a role."""
        role = await Role.get_or_none(id=role_id)
        if not role:
            return []
        permissions = await role.permissions.all()
        return [
            PermissionDTO.model_validate(permission)
            for permission in permissions
        ]

    async def assign_permission_to_role(self, role_id: UUID,
                                        permission_id: UUID) -> bool:
        """Assign a permission to a role."""
        role = await Role.get_or_none(id=role_id)
        permission = await Permission.get_or_none(id=permission_id)
        if not role or not permission:
            return False
        await role.permissions.add(permission)
        return True

    async def remove_permission_from_role(self, role_id: UUID,
                                          permission_id: UUID) -> bool:
        """Remove a permission from a role."""
        role = await Role.get_or_none(id=role_id)
        permission = await Permission.get_or_none(id=permission_id)
        if not role or not permission:
            return False
        await role.permissions.remove(permission)
        return True
